home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
WINDOWS
/
WINPOEM.ARJ
/
WINPOEM.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-03
|
43KB
|
1,546 lines
/**************************************************************************
* WinPoem *
* *
* A small C++ program which displays a random poem on execution. *
* It also allows search for poems containing a string. *
* It requires winpoem.dat and creates winpoem.idx. *
* *
* Copyright 1992 Julian Smart, email jacs@aiai.ed.ac.uk *
* *
* Filename: poetry.cpp *
* Purpose: Main source file for WinPoem. *
* Version: 1.0 *
*************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define buf_size 3000
#define DEFAULT_POETRY_DAT "winpoem"
#define DEFAULT_POETRY_IND "winpoem"
#define DEFAULT_CHAR_HEIGHT 18
#define DEFAULT_FONT "Swiss"
#define DEFAULT_X_POS 0
#define DEFAULT_Y_POS 0
#define BORDER_SIZE 30
#define THIN_LINE_BORDER 10
#define THICK_LINE_BORDER 16
#define THICK_LINE_WIDTH 2
#define SHADOW_OFFSET 1
#define X_SIZE 30
#define Y_SIZE 20
static char poem_buffer[buf_size]; // Storage for each poem
static char line[120]; // Storage for a line
static char title[120]; // Remember the title
static char search_string[120]; // The search string
static int pages[20]; // For multipage poems -
// store the start of each page
static long last_poem_start = 0; // Start of last found poem
static long last_find = -1; // Point in file of last found
// search string
static BOOL search_ok = FALSE; // Search was successful
static BOOL same_search = FALSE; // Searching on same string
static long index[600]; // Index of poem starts
static long nitems = 0; // Number of poems
static int desired_char_height = DEFAULT_CHAR_HEIGHT; // Desired height
static char DesiredFont[64]; // Chosen font
static int char_height = DEFAULT_CHAR_HEIGHT; // Actual height
static int index_ptr = -1; // Pointer into index
static int poem_height, poem_width; // Size of poem window
static HWND GlobalWindow; // Window handle
static HANDLE bitmap = NULL; // Window backing bitmap
static HMENU PopupMenu; // WinPoem menu
static int XPos; // Startup X position
static int YPos; // Startup Y position
static char index_filename[100]; // Index filename
static char data_filename[100]; // Data filename
static char error_buf[200]; // Error message buffer
static BOOL loaded_ok = FALSE; // Poem loaded ok
static BOOL index_ok = FALSE; // Index loaded ok
static BOOL paging = FALSE; // Are we paging?
static int current_page = 0; // Currently viewed page
static HICON Corner1; // Shell corner icons
static HICON Corner2;
static HICON Corner3;
static HICON Corner4;
static HPEN WhitePen; // Pens
static HPEN BlackPen;
static HPEN GreyPen;
static HBRUSH GreyBrush;
static HBRUSH DarkGreyBrush;
// Fonts
static HFONT NormalFont = NULL; // Fonts
static HFONT BoldFont = NULL;
static HFONT ItalicFont = NULL;
void PoetryError(char *);
void PoetryNotify(char *Msg);
void InitPoetry();
void TryLoadIndex();
BOOL LoadPoem(char *, long);
int GetIndex();
int LoadIndex(char *);
void LogMessage(char *Msg);
void LogInitialize();
BOOL Compile();
void WritePreferences();
void ReadPreferences();
void DeleteFonts(void);
void FindMax(int *max_thing, int thing);
void CreateFonts();
void CopyToClipboard(HWND, char *);
BOOL FAR PASCAL _export AboutDlgProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam);
long FAR PASCAL _export WndProc( HWND hWnd, WORD iMessage,
WORD wParam, LONG lParam );
BOOL FAR PASCAL _export SearchDlgProc(HWND hDlg, unsigned message,
WORD wParam, LONG lParam);
class Main
{
public:
static HANDLE hInstance;
static HANDLE hPrevInstance;
static int nCmdShow;
static int MessageLoop( void );
};
HANDLE Main::hInstance = 0;
HANDLE Main::hPrevInstance = 0;
int Main::nCmdShow = 0;
// Message loop
int Main::MessageLoop( void )
{
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam;
}
// Base class
class Window
{
protected:
HWND hWnd;
public:
// Provide (read) access to the window's handle in case it is needed
// elsewhere.
HWND GetHandle( void ) { return hWnd; }
BOOL Show( int nCmdShow ) { return ShowWindow( hWnd, nCmdShow ); }
void Update( void ) { UpdateWindow( hWnd ); }
// Pure virtual function makes Window an abstract class.
virtual long WndProc( WORD iMessage, WORD wParam, LONG lParam ) = 0;
};
class MainWindow : public Window
{
private:
static char szClassName[14];
public:
// Register the class only AFTER WinMain assigns appropriate
// values to static members of Main and only if no previous
// instances of the program exist (a previous instance would
// have already performed the registration).
static void Register( void )
{
WNDCLASS wndclass; // Structure used to register Windows class.
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = ::WndProc;
wndclass.cbClsExtra = 0;
// Reserve extra bytes for each instance of the window;
// we will use these bytes to store a pointer to the C++
// (MainWindow) object corresponding to the window.
// the size of a 'this' pointer depends on the memory model.
wndclass.cbWndExtra = sizeof( MainWindow * );
wndclass.hInstance = Main::hInstance;
wndclass.hIcon = LoadIcon( Main::hInstance, "winpoem" );
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndclass.hbrBackground = GetStockObject( LTGRAY_BRUSH );
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szClassName;
if ( ! RegisterClass( &wndclass ) )
exit( FALSE );
}
// Do not create unless previously registered.
MainWindow( void )
{
// Pass 'this' pointer in lpParam of CreateWindow().
hWnd = CreateWindow( szClassName,
szClassName,
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE,
XPos, YPos,
X_SIZE, SW_HIDE,
NULL, NULL, Main::hInstance,
(LPSTR) this );
GlobalWindow = hWnd;
if ( ! hWnd )
exit( FALSE );
Show( Main::nCmdShow );
}
long WndProc( WORD iMessage, WORD wParam, LONG lParam );
// Print a message in the client rectangle.
void Paint( void );
// Display next page or poem
void NextPage(HWND);
// Display previous page
void PreviousPage(HWND);
// User search
void Search(HWND, BOOL);
// Look in file for string
long DoSearch();
// Do the actual drawing of text (or just calculate size needed)
void ScanBuffer(BOOL DrawIt, int *max_x, int *max_y);
// Load the poem
void GetIndexLoadPoem(void);
void Resize();
// Respond to a command menu message
BOOL Command(WORD);
// Respond to a keypress
void KeyDown(WORD);
void Char(WORD);
// Change text height (refresh screen)
void ChangeHeight(int);
};
char MainWindow::szClassName[] = "WinPoem";
// Paint procedure
void MainWindow::Paint( void )
{
int max_x, max_y;
PAINTSTRUCT ps;
RECT rect;
HDC hdcMem = NULL;
HDC hdc;
// If we have a bitmap with a poem drawn on it,
// whack it onto the window.
if (bitmap)
{
GetClientRect( hWnd, (LPRECT) &rect );
hdc = BeginPaint( hWnd, &ps );
hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem, bitmap);
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
}
else
{
// Necessary default behaviour
(void)BeginPaint( hWnd, &ps );
EndPaint(hWnd, &ps);
}
}
// Change the text height and redraw
void MainWindow::ChangeHeight(int inc)
{
PAINTSTRUCT ps;
TEXTMETRIC lpTextMetric;
HDC hdc = BeginPaint( hWnd, &ps );
SelectObject(hdc, NormalFont);
GetTextMetrics(hdc, &lpTextMetric);
int old_height = lpTextMetric.tmHeight;
int actual_height = old_height;
// Keep changing font size until it really changes height
while (actual_height == old_height && desired_char_height > 1
&& desired_char_height < 40)
{
desired_char_height += inc;
CreateFonts();
// See what ACTUAL char height is
SelectObject(hdc, NormalFont);
GetTextMetrics(hdc, &lpTextMetric);
actual_height = lpTextMetric.tmHeight;
}
// Stop ChangeHeight from getting stuck next time
if (desired_char_height == 1)
desired_char_height = 2;
if (desired_char_height == 40)
desired_char_height = 39;
EndPaint(hWnd, &ps);
Resize();
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
}
// Create the fonts
void CreateFonts()
{
// Create fonts
BYTE Font;
char *TypeFace = "Any";
if (strcmp(DesiredFont, "Modern") == 0)
Font = FF_MODERN;
else if (strcmp(DesiredFont, "Script") == 0)
Font = FF_SCRIPT;
else if (strcmp(DesiredFont, "Swiss") == 0)
Font = FF_SWISS;
else if (strcmp(DesiredFont, "Roman") == 0)
Font = FF_ROMAN;
else if (strcmp(DesiredFont, "Decorative") == 0)
Font = FF_DECORATIVE;
else
Font = FF_DONTCARE;
if (!NormalFont)
DeleteObject(NormalFont);
NormalFont = CreateFont(desired_char_height, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH | Font,
TypeFace);
if (!ItalicFont)
DeleteObject(ItalicFont);
ItalicFont = CreateFont(desired_char_height, 0, 0, 0, FW_BOLD, 1, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH | Font,
TypeFace);
if (!BoldFont)
DeleteObject(BoldFont);
BoldFont = CreateFont(desired_char_height, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH | Font,
TypeFace);
}
// Delete fonts
void DeleteFonts(void)
{
DeleteObject(NormalFont);
DeleteObject(BoldFont);
DeleteObject(ItalicFont);
}
// Read the poetry buffer, either for finding the size
// or for writing to a bitmap (not to the window directly,
// since that displays messily)
// If DrawIt is true, we draw, otherwise we just determine the
// size the window should be.
void MainWindow::ScanBuffer(BOOL DrawIt, int *max_x, int *max_y)
{
PAINTSTRUCT ps;
RECT rect;
TEXTMETRIC lpTextMetric;
HDC hdc = BeginPaint( hWnd, &ps );
HDC hdcMem = NULL;
int i = pages[current_page];
int ch = -1;
short x = 10;
short y = 0;
int j;
char *line_ptr;
int strsize;
int loword;
int x1;
DWORD extent;
int curr_width = 0;
BOOL page_break = FALSE;
short width = 0;
short height = 0;
SetBkMode(hdc, TRANSPARENT);
if (DrawIt)
{
width = *max_x;
height = *max_y;
rect.left = 0; rect.top = 0;
rect.right = width; rect.bottom = height;
y = (height - (poem_height))/2;
if (bitmap)
{
DeleteObject(bitmap);
bitmap = NULL;
}
hdcMem = CreateCompatibleDC(hdc);
if (hdcMem)
{
bitmap = CreateCompatibleBitmap(hdc, width, height);
if (bitmap)
{
SelectObject(hdcMem, bitmap);
SetBkMode(hdcMem, TRANSPARENT);
FillRect( hdcMem, &rect, GetStockObject( LTGRAY_BRUSH ) );
}
else
{
DeleteDC(hdcMem);
hdcMem = hdc;
}
}
}
// See what ACTUAL char height is
SelectObject(hdc, NormalFont);
GetTextMetrics(hdc, &lpTextMetric);
char_height = lpTextMetric.tmHeight;
if (current_page == 0)
title[0] = 0;
else if (title[0] != 0)
{
SelectObject(hdc, BoldFont);
strsize = strlen(title);
extent = GetTextExtent(hdc, title, strsize);
loword = LOWORD(extent);
FindMax(&curr_width, loword);
if (DrawIt)
{
x1 = width - loword;
x = x1/2;
SelectObject(hdcMem, BoldFont);
// Change text to WHITE!
SetTextColor(hdcMem, RGB(0, 0, 0));
TextOut(hdcMem, x, y, title, strsize);
// Change text to BLACK!
SetTextColor(hdcMem, RGB(255, 255, 255));
TextOut(hdcMem, x-SHADOW_OFFSET, y-SHADOW_OFFSET, title, strsize);
SetTextColor(hdcMem, RGB(0, 0, 0));
}
y += char_height;
y += char_height;
}
while (ch != 0 && !page_break)
{
j = 0;
while (((ch = poem_buffer[i]) != 13) && (ch != 0))
{
line[j] = ch;
j ++;
i ++;
}
if (ch == 13)
{
ch = -1;
i ++;
// Add another to skip the linefeed
i ++;
// If a single newline on its own, put a space in
if (j == 0)
{
line[j] = ' ';
j ++;
line[j] = 0;
}
}
if (j > 0)
{
line[j] = 0;
if (line[0] == '@')
{
switch (line[1])
{
case 'P':
paging = TRUE;
page_break = TRUE;
break;
case 'T':
SelectObject(hdc, BoldFont);
line_ptr = line+3;
strsize = strlen(line_ptr);
strcpy(title, line_ptr);
strcat(title, " (cont'd)");
extent = GetTextExtent(hdc, line_ptr, strsize);
loword = LOWORD(extent);
FindMax(&curr_width, loword);
if (DrawIt)
{
x1 = width - loword;
x = x1/2;
SelectObject(hdcMem, BoldFont);
// Change text to WHITE!
SetTextColor(hdc, RGB(0, 0, 0));
TextOut(hdcMem, x, y, line_ptr, strsize);
// Change text to BLACK!
SetTextColor(hdcMem, RGB(255, 255, 255));
TextOut(hdcMem, x-SHADOW_OFFSET, y-SHADOW_OFFSET, line_ptr, strsize);
SetTextColor(hdcMem, RGB(0, 0, 0));
}
break;
case 'A':
line_ptr = line+3;
SelectObject(hdc, ItalicFont);
strsize = strlen(line_ptr);
extent = GetTextExtent(hdc, line_ptr, strsize);
loword = LOWORD(extent);
FindMax(&curr_width, loword);
if (DrawIt)
{
x1 = width - loword;
x = x1/2;
SelectObject(hdcMem, ItalicFont);
SetTextColor(hdcMem, RGB(0, 0, 0));
TextOut(hdcMem, x, y, line_ptr, strsize);
}
break;
// Default: just ignore this line
default:
y -= char_height;
}
}
else
{
SelectObject(hdc, NormalFont);
strsize = strlen(line);
extent = GetTextExtent(hdc, line, strsize);
int loword = LOWORD(extent);
FindMax(&curr_width, loword);
if (DrawIt)
{
x1 = width - loword;
int x = x1/2;
SelectObject(hdcMem, NormalFont);
SetTextColor(hdcMem, RGB(0, 0, 0));
TextOut(hdcMem, x, y, line, strsize);
}
}
}
y += char_height;
}
// Write (cont'd)
if (page_break)
{
char *cont = "(cont'd)";
SelectObject(hdc, NormalFont);
strsize = strlen(cont);
extent = GetTextExtent(hdc, cont, strsize);
int loword = LOWORD(extent);
FindMax(&curr_width, loword);
if (DrawIt)
{
x1 = width - loword;
int x = x1/2;
SelectObject(hdcMem, NormalFont);
SetTextColor(hdcMem, RGB(255, 255, 255));
TextOut(hdcMem, x, y, cont, strsize);
}
y += 2*char_height;
}
*max_x = curr_width;
*max_y = y-char_height;
if (page_break)
pages[current_page+1] = i;
else
paging = FALSE;
if (DrawIt)
{
// Draw dark grey thick border
SelectObject(hdcMem, DarkGreyBrush);
SelectObject(hdcMem, GreyPen);
// Left side
Rectangle(hdcMem, 0, THIN_LINE_BORDER, THIN_LINE_BORDER, height-THIN_LINE_BORDER);
// Top side
Rectangle(hdcMem, THIN_LINE_BORDER, 0, width-THIN_LINE_BORDER, THIN_LINE_BORDER);
// Right side
Rectangle(hdcMem, width-THIN_LINE_BORDER, THIN_LINE_BORDER, width, height-THIN_LINE_BORDER);
// Bottom side
Rectangle(hdcMem, THIN_LINE_BORDER, height-THIN_LINE_BORDER, width-THIN_LINE_BORDER, height);
// Draw border
// Have grey background, plus 3-d border -
// One black rectangle.
// Inside this, left and top sides - dark grey. Bottom and right -
// white.
// Change pen to black
SelectObject(hdcMem, BlackPen);
MoveTo(hdcMem, THIN_LINE_BORDER, THIN_LINE_BORDER);
LineTo(hdcMem, width-THIN_LINE_BORDER, THIN_LINE_BORDER);
LineTo(hdcMem, width-THIN_LINE_BORDER, height-THIN_LINE_BORDER);
LineTo(hdcMem, THIN_LINE_BORDER, height-THIN_LINE_BORDER);
LineTo(hdcMem, THIN_LINE_BORDER, THIN_LINE_BORDER);
// Right and bottom white lines
SelectObject(hdcMem, WhitePen);
MoveTo(hdcMem, width-THICK_LINE_BORDER,
THICK_LINE_BORDER);
LineTo(hdcMem, width-THICK_LINE_BORDER,
height-THICK_LINE_BORDER);
LineTo(hdcMem, THICK_LINE_BORDER,
height-THICK_LINE_BORDER);
// Left and top grey lines
SelectObject(hdcMem, GreyPen);
LineTo(hdcMem, THICK_LINE_BORDER, THICK_LINE_BORDER);
LineTo(hdcMem, width-THICK_LINE_BORDER, THICK_LINE_BORDER);
// Draw icons
SelectObject(hdcMem, BlackPen);
DrawIcon(hdcMem, 0, 0, Corner1);
DrawIcon(hdcMem, width-32, 0, Corner2);
int y2 = height - 32;
int x2 = (width-32);
DrawIcon(hdcMem, 0, y2, Corner3);
DrawIcon(hdcMem, x2, y2, Corner4);
DeleteDC(hdcMem);
}
EndPaint(hWnd, &ps);
}
// Get an index (randomly generated) and load the poem
void MainWindow::GetIndexLoadPoem(void)
{
if (index_ok)
index_ptr = GetIndex();
if (index_ptr > -1)
loaded_ok = LoadPoem(data_filename, -1);
}
// Find the size of the poem and resize the window accordingly
void MainWindow::Resize()
{
int max_x, max_x1;
int max_y, max_y1;
RECT Rect;
RECT ClientRect;
GetWindowRect(GetHandle(), &Rect);
GetClientRect( hWnd, (LPRECT) &ClientRect );
// Calculate what to add on for the window borders & menu bar
int DiffX = (Rect.right - Rect.left) - ClientRect.right;
int DiffY = (Rect.bottom - Rect.top) - ClientRect.bottom;
// Get the poem size
ScanBuffer(FALSE, &poem_width, &poem_height);
max_x = poem_width + (2*BORDER_SIZE);
max_y = poem_height + (2*BORDER_SIZE);
max_x1 = max_x;
max_y1 = max_y;
// Actually draw it
ScanBuffer(TRUE, &max_x1, &max_y1);
MoveWindow(GetHandle(), Rect.left, Rect.top, max_x+DiffX, max_y+DiffY, TRUE);
SetFocus(GetHandle());
}
// Which is more?
void FindMax(int *max_thing, int thing)
{
if (thing > *max_thing)
*max_thing = thing;
}
// Process menu commands
// Return TRUE if processed one
BOOL MainWindow::Command(WORD Item)
{
HWND handle = GetHandle();
FARPROC lpProcAbout;
switch (Item)
{
case 101:
// Another poem/page
NextPage(handle);
break;
case 113:
// Previous page
PreviousPage(handle);
break;
case 114:
// Search - with dialog
Search(handle, TRUE);
break;
case 115:
// Search - without dialog (next match)
Search(handle, FALSE);
break;
case 116:
// Copy current poem to the clipboard
CopyToClipboard(handle, poem_buffer);
break;
case 105:
// Bigger text
ChangeHeight(1);
break;
case 106:
// Smaller text
ChangeHeight(-1);
break;
case 107:
strcpy(DesiredFont, "Roman");
DeleteFonts();
CreateFonts();
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
break;
case 108:
strcpy(DesiredFont, "Swiss");
DeleteFonts();
CreateFonts();
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
break;
case 109:
strcpy(DesiredFont, "Modern");
DeleteFonts();
CreateFonts();
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
break;
case 110:
strcpy(DesiredFont, "Script");
DeleteFonts();
CreateFonts();
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
break;
case 111:
strcpy(DesiredFont, "Decorative");
DeleteFonts();
CreateFonts();
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
break;
case 112:
strcpy(DesiredFont, "Any");
DeleteFonts();
CreateFonts();
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
break;
case 102:
// Compile index
Compile();
break;
case 103:
// About
lpProcAbout = MakeProcInstance((FARPROC)AboutDlgProc, Main::hInstance);
DialogBox(Main::hInstance, "DIALOG_1", handle, lpProcAbout);
FreeProcInstance(lpProcAbout);
break;
case 104:
// Exit
SendMessage(handle, WM_CLOSE, 0, 0L);
break;
default:
return FALSE;
}
return TRUE;
}
// Next page/poem
void MainWindow::NextPage(HWND handle)
{
if (paging)
current_page ++;
else
{
current_page = 0;
GetIndexLoadPoem();
}
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
}
// Previous page
void MainWindow::PreviousPage(HWND handle)
{
if (current_page > 0)
{
current_page --;
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
}
}
// Search for a string
void MainWindow::Search(HWND handle, BOOL ask)
{
FARPROC lpProcSearch;
long position;
if (ask || (search_string[0] == 0))
{
lpProcSearch = MakeProcInstance((FARPROC)SearchDlgProc, Main::hInstance);
DialogBox(Main::hInstance, "DIALOG_2", handle, lpProcSearch);
FreeProcInstance(lpProcSearch);
}
else
{
same_search = TRUE;
search_ok = TRUE;
}
if (search_ok)
{
position = DoSearch();
if (position > -1)
{
loaded_ok = LoadPoem(data_filename, position);
Resize();
InvalidateRect(handle, NULL, TRUE);
UpdateWindow(handle);
}
else
{
last_poem_start = 0;
PoetryNotify("Search string not found.");
}
}
}
// Process non-character key presses
void MainWindow::KeyDown(WORD Item)
{
HWND handle = GetHandle();
switch (Item)
{
case VK_SPACE:
case VK_NEXT:
// Another poem
NextPage(handle);
break;
case VK_ESCAPE:
SendMessage(handle, WM_CLOSE, 0, 0L);
break;
case VK_PRIOR:
PreviousPage(handle);
break;
default:
break;
}
}
// Process characters
void MainWindow::Char(WORD Item)
{
HWND handle = GetHandle();
switch (Item)
{
case 'n':
case 'N':
// Next match
Search(handle, FALSE);
break;
case 's':
case 'S':
// New search
Search(handle, TRUE);
break;
default:
break;
}
}
// Copy a string to the clipboard
void CopyToClipboard(HWND handle, char *s)
{
int length = strlen(s);
HANDLE hGlobalMemory = GlobalAlloc(GHND, (DWORD) length + 1);
if (hGlobalMemory)
{
LPSTR lpGlobalMemory = GlobalLock(hGlobalMemory);
int i, j = 0;
for (i = 0; i < length; i ++)
{
if (s[i] == '@')
{
i++;
switch (s[i])
{
case 'P':
break;
case 'T':
case 'A':
default:
i ++;
break;
}
}
else
{
lpGlobalMemory[j] = s[i];
j ++;
}
}
GlobalUnlock(hGlobalMemory);
OpenClipboard(handle);
EmptyClipboard();
SetClipboardData(CF_TEXT, hGlobalMemory);
CloseClipboard();
}
}
// Maind window procedure
long MainWindow::WndProc( WORD iMessage, WORD wParam, LONG lParam )
{
RECT ClientRect;
POINT point;
switch (iMessage)
{
case WM_CREATE:
break;
case WM_PAINT:
Paint();
break;
// Right button - popup the menu
case WM_RBUTTONDOWN:
point = MAKEPOINT(lParam);
ClientToScreen(GetHandle(), &point);
TrackPopupMenu(PopupMenu, 0, point.x, point.y, 0, GetHandle(), NULL);
break;
case WM_DESTROY:
WritePreferences();
DeleteFonts();
DeleteObject(GreyPen);
DeleteObject(WhitePen);
// DestroyMenu(PopupMenu);
if (bitmap)
DeleteObject(bitmap);
PostQuitMessage( 0 );
break;
case WM_SYSCOMMAND:
// For some reason this doesn't work, i.e.
// the window is shown before this can take effect
if(wParam == SC_RESTORE)
ShowWindow(hWnd, SW_HIDE);
if (!Command(wParam))
{
DefWindowProc( hWnd, iMessage, wParam, lParam );
// When we restore, get another poem
if(wParam == SC_RESTORE)
{
NextPage(hWnd);
ShowWindow(hWnd, SW_SHOW);
SetFocus(hWnd);
}
}
break;
case WM_COMMAND:
Command(wParam);
break;
case WM_KEYDOWN:
KeyDown(wParam);
break;
case WM_CHAR:
Char(wParam);
break;
default:
return DefWindowProc( hWnd, iMessage, wParam, lParam );
}
}
// If data pointers are near pointers
#if defined(__SMALL__) || defined(__MEDIUM__)
inline Window *GetPointer( HWND hWnd )
{
return (Window *) GetWindowWord( hWnd, 0 );
}
inline void SetPointer( HWND hWnd, Window *pWindow )
{
SetWindowWord( hWnd, 0, (WORD) pWindow );
}
// else pointers are far
#elif defined(__LARGE__) || defined(__COMPACT__)
inline Window *GetPointer( HWND hWnd )
{
return (Window *) GetWindowLong( hWnd, 0 );
}
inline void SetPointer( HWND hWnd, Window *pWindow )
{
SetWindowLong( hWnd, 0, (LONG) pWindow );
}
#else
#error Choose another memory model!
#endif
// Main window procedure - C function calls C++ version
long FAR PASCAL _export WndProc( HWND hWnd, WORD iMessage, WORD wParam,
LONG lParam )
{
// Pointer to the (C++ object that is the) window.
Window *pWindow = GetPointer( hWnd );
// The pointer pWindow will have an invalid value if the WM_CREATE
// message has not yet been processed (we respond to the WM_CREATE
// message by setting the extra bytes to be a pointer to the
// (C++) object corresponding to the Window identified
// by hWnd). The messages that
// precede WM_CREATE must be processed without using pWindow so we
// pass them to DefWindowProc.
// How do we know in general if the pointer pWindow is invalid?
// Simple: Windows allocates the window extra bytes using LocalAlloc
// which zero initializes memory; thus, pWindow will have a value of
// zero before we set the window extra bytes to the 'this' pointer.
// Caveat emptor: the fact that LocalAlloc will zero initialize the
// window extra bytes is not documented; therefore, it could change
// in the future.
if ( pWindow == 0 )
{
if ( iMessage == WM_CREATE )
{
LPCREATESTRUCT lpcs;
lpcs = (LPCREATESTRUCT) lParam;
pWindow = (Window *) lpcs->lpCreateParams;
// Store a pointer to this object in the window's extra bytes;
// this will enable to access this object (and its member
// functions) in WndProc where we are
// given only a handle to identify the window.
SetPointer( hWnd, pWindow );
// Now let the object perform whatever
// initialization it needs for WM_CREATE in its own
// WndProc.
return pWindow->WndProc( iMessage, wParam, lParam );
}
else
return DefWindowProc( hWnd, iMessage, wParam, lParam );
}
else
return pWindow->WndProc( iMessage, wParam, lParam );
}
// Turn off warning: Parameter 'lpszCmdLine' is never used in function WinMain(unsigned int,unsigned int,char far*,int)
#pragma argsused
// Turn off warning: 'MainWnd' is assigned a value that is never used in function WinMain(unsigned int,unsigned int,char far*,int)
#pragma option -w-aus
// Main windows entry point
int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
int nCmdShow )
{
// Initialize the debugging log - development only
// LogInitialize();
ReadPreferences();
Main::hInstance = hInstance;
Main::hPrevInstance = hPrevInstance;
Main::nCmdShow = nCmdShow;
// A Windows class should be registered with Windows before any windows
// of that type are created.
// Register here all Windows classes that will be used in the program.
// Windows classes should not be registered if an instance of
// the program is already running.
if ( ! Main::hPrevInstance ) {
MainWindow::Register();
}
randomize();
pages[0] = 0;
search_string[0] = 0;
MainWindow MainWnd;
PopupMenu = LoadMenu(Main::hInstance, "MENU_1");
HMENU SystemMenu = GetSystemMenu(MainWnd.GetHandle(), FALSE);
DeleteMenu(SystemMenu, SC_SIZE, MF_BYCOMMAND);
DeleteMenu(SystemMenu, SC_MAXIMIZE, MF_BYCOMMAND);
AppendMenu(SystemMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(SystemMenu, MF_POPUP | MF_STRING, PopupMenu, "WinPoem Options");
InitPoetry();
CreateFonts();
Corner1 = LoadIcon(hInstance, "ICON_1");
Corner2 = LoadIcon(hInstance, "ICON_2");
Corner3 = LoadIcon(hInstance, "ICON_3");
Corner4 = LoadIcon(hInstance, "ICON_4");
BlackPen = GetStockObject(BLACK_PEN);
GreyPen = CreatePen(PS_SOLID, THICK_LINE_WIDTH, RGB(100, 100, 100));
WhitePen = CreatePen(PS_SOLID, THICK_LINE_WIDTH, RGB(255, 255, 255));
GreyBrush = GetStockObject(LTGRAY_BRUSH);
DarkGreyBrush = GetStockObject(GRAY_BRUSH);
if (nCmdShow == SW_SHOWNORMAL)
{
MainWnd.GetIndexLoadPoem();
MainWnd.Resize();
}
return Main::MessageLoop();
}
// Load index file
int LoadIndex(char *file_name)
{
long data;
FILE *index_file;
int i = 0;
char buf[100];
if (file_name)
sprintf(buf, "%s.idx", file_name);
if (! (file_name && (index_file = fopen(buf, "r"))))
return 0;
else
{
fscanf(index_file, "%ld", &nitems);
for (i = 0; i < nitems; i++)
{
fscanf(index_file, "%ld", &data);
index[i] = data;
}
fclose(index_file);
return 1;
}
}
// Get index
int GetIndex()
{
int indexn = 0;
double a, b;
indexn = rand() % nitems;
if ((indexn < 0) || (indexn > nitems))
{ PoetryError("No such poem!");
return -1;
}
else
return indexn;
}
// Read preferences
void ReadPreferences()
{
GetProfileString("WinPoem", "Font", DEFAULT_FONT, DesiredFont, 64);
desired_char_height = GetProfileInt("WinPoem", "TextSize", DEFAULT_CHAR_HEIGHT);
XPos = GetProfileInt("WinPoem", "X", DEFAULT_X_POS);
YPos = GetProfileInt("WinPoem", "Y", DEFAULT_Y_POS);
}
// Write preferences to disk
void WritePreferences()
{
char ProfileString[50];
RECT Rect;
sprintf(ProfileString, "%d", desired_char_height);
WriteProfileString("WinPoem", "TextSize", ProfileString);
WriteProfileString("WinPoem", "Font", DesiredFont);
GetWindowRect(GlobalWindow, &Rect);
sprintf(ProfileString, "%d", Rect.left);
WriteProfileString("WinPoem", "X", ProfileString);
sprintf(ProfileString, "%d", Rect.top);
WriteProfileString("WinPoem", "Y", ProfileString);
}
// Load a poem from given file, at given point in file.
// If position is > -1, use this for the position in the
// file, otherwise use index[index_ptr] to find the correct position.
BOOL LoadPoem(char *file_name, long position)
{
char ch = 0;
int i = 0;
int j = 0;
int indexn = 0;
char buf[100];
long data;
FILE *data_file;
paging = FALSE;
current_page = 0;
if (file_name)
sprintf(buf, "%s.dat", file_name);
if (! (file_name && (data_file = fopen(buf, "r"))))
{
sprintf(error_buf, "Data file %s not found.", buf);
PoetryError(error_buf);
return FALSE;
}
else
{
if (position > -1)
data = position;
else
data = index[index_ptr];
fseek(data_file, data, SEEK_SET);
ch = 0;
i = 0;
while ((ch != EOF) && (ch != '#'))
{
ch = getc(data_file);
// Add a linefeed so it will copy to the clipboard ok
if (ch == 10)
{
poem_buffer[i] = 13;
i++;
}
poem_buffer[i] = ch;
i ++;
if (i == buf_size)
{
sprintf(error_buf, "%s", "Poetry buffer exceeded.");
PoetryError(error_buf);
return FALSE;
}
}
fclose(data_file);
poem_buffer[i-1] = 0;
return TRUE;
}
}
// Do the search
long MainWindow::DoSearch()
{
FILE *file;
long i = 0;
char ch = 0;
char buf[100];
long find_start;
long previous_poem_start;
BOOL found = FALSE;
int search_length = strlen(search_string);
if (same_search)
{
find_start = last_find + 1;
previous_poem_start = last_poem_start;
}
else
{
find_start = 0;
last_poem_start = 0;
previous_poem_start = -1;
}
if (data_filename)
sprintf(buf, "%s.dat", data_filename);
if (! (data_filename && (file = fopen(buf, "r"))))
{
sprintf(error_buf, "Poetry data file %s not found\n", buf);
PoetryError(error_buf);
return FALSE;
}
fseek(file, find_start, SEEK_SET);
while ((ch != EOF) && !found)
{
ch = getc(file);
ch |= 0x0020; // Make lower case
// Only match if we're looking at a different poem
// (no point in displaying the same poem again)
if ((ch == search_string[i]) && (last_poem_start != previous_poem_start))
{
if (i == 0)
last_find = ftell(file);
if (i == search_length-1)
found = TRUE;
i ++;
}
else
i = 0;
if (ch == '#')
{
ch = getc(file);
last_poem_start = ftell(file);
}
}
fclose(file);
if (ch == EOF)
last_find = -1;
if (found)
{
return last_poem_start;
}
else
return -1;
}
// Set up poetry filenames, preferences, load the index
void InitPoetry()
{
strcpy(index_filename, DEFAULT_POETRY_IND);
strcpy(data_filename, DEFAULT_POETRY_DAT);
TryLoadIndex();
}
// Load index (or compile it if none found)
void TryLoadIndex()
{
index_ok = LoadIndex(index_filename);
if (!index_ok)
{
PoetryError("Index file not found; will compile new one");
index_ok = Compile();
}
}
// Error message
void PoetryError(char *Msg)
{
MessageBox(GlobalWindow, (LPSTR)Msg, (LPSTR)"Error", MB_OK | MB_ICONEXCLAMATION);
}
// Notification (change icon to something appropriate!)
void PoetryNotify(char *Msg)
{
MessageBox(GlobalWindow, (LPSTR)Msg, (LPSTR)"Notification", MB_OK |
MB_ICONINFORMATION);
}
// Initialize a log file (for debugging purposes)
void LogInitialize()
{
char *logfile_name = "c:\\log";
OFSTRUCT OfStruct; // Information from OpenFile()
int WinFile;
WinFile = OpenFile(logfile_name, &OfStruct, OF_CREATE);
_lclose(WinFile);
}
// Write a message to the log file
void LogMessage(char *Msg)
{
char *logfile_name = "c:\\log";
FILE *logfile;
OFSTRUCT OfStruct; // Information from OpenFile()
int WinFile;
if ((WinFile = OpenFile(logfile_name, &OfStruct, OF_READWRITE)) != -1)
{
logfile = fdopen(WinFile, "a");
fprintf(logfile, "%s\n", Msg);
fclose(logfile);
}
}
// 'About' dialog box
BOOL FAR PASCAL AboutDlgProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (wParam)
{
case 101:
EndDialog(hDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
// Build up and save an index into the poetry data file, for
// rapid random access
BOOL Compile()
{
FILE *file;
long i = 0;
int j;
char ch = 0;
char buf[100];
if (data_filename)
sprintf(buf, "%s.dat", data_filename);
if (! (data_filename && (file = fopen(buf, "r"))))
{
sprintf(error_buf, "Poetry data file %s not found\n", buf);
PoetryError(error_buf);
return FALSE;
}
nitems = 0;
// Do first one (?)
index[nitems] = 0;
nitems ++;
// Do rest
while (ch != EOF)
{
ch = getc(file);
i ++;
if (ch == '#')
{
ch = getc(file);
long data;
data = ftell(file);
index[nitems] = data;
nitems ++;
}
}
fclose(file);
if (index_filename)
sprintf(buf, "%s.idx", index_filename);
if (! (data_filename && (file = fopen(buf, "w"))))
{
sprintf(error_buf, "Poetry index file %s cannot be created\n", buf);
PoetryError(error_buf);
return FALSE;
}
fprintf(file, "%ld\n\n", nitems);
for (j = 0; j < nitems; j++)
fprintf(file, "%ld\n", index[j]);
fclose(file);
PoetryNotify("Poetry index compiled.");
return TRUE;
}
// Dialog proc for entering search string
BOOL FAR PASCAL SearchDlgProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
char Text[120];
switch (message)
{
case WM_INITDIALOG:
if (search_string[0] != 0)
SetDlgItemText(hDlg, 101, search_string);
return TRUE;
case WM_COMMAND:
switch (wParam)
{
case 101:
// Edit
return TRUE;
// Ok
case 102:
// Find string
GetDlgItemText(hDlg, 101, Text, 40);
if (strcmp(Text, search_string) == 0)
same_search = TRUE;
else
same_search = FALSE;
strcpy(search_string, Text);
search_ok = TRUE;
EndDialog(hDlg, 0);
return TRUE;
// Cancel
case 103:
EndDialog(hDlg, 0);
search_ok = FALSE;
return TRUE;
}
break;
}
return FALSE;
}